/*
 * Copyright (C) 2003, Velocityme Partnership
 * KeySessionBean.java
 *
 * Created on 12 April 2003, 07:18
 */

package com.velocityme.session;

import com.velocityme.entity.LoginStatusBean;
import javax.ejb.*;
import java.util.*;

import javax.naming.*;

import com.velocityme.interfaces.*;
import com.velocityme.utility.LicenceManager;
import com.velocityme.utility.PasswordEncrypter;
import com.velocityme.utility.SetupDatabase;
import java.rmi.RemoteException;
import org.apache.log4j.Logger;

/**
 *
 * @author  Robert Crida Work
 * @ejb.bean
 *           type="Stateful"
 *           cmp-version="2.x"
 *           name="KeySession"
 *           jndi-name="ejb/KeySession"
 *           view-type="both"
 *           transaction-type="Container"
 * @ejb.transaction type="Required"
 *
 * @ejb.util generate="physical"
 *
 */
public class KeySessionBean implements SessionBean {
    
    private SessionContext m_context;
    
    private LoginLocal m_loginLocal;
    
    private LoginStatusLocal m_statusLoggedOn;

    private Logger m_logger = Logger.getLogger(KeySessionBean.class);
    
    public static final int LOGIN_SUCCESS = 0;
    public static final int LOGIN_LICENCE = 1;
    public static final int LOGIN_PASSWORD = 2;
    public static final int LOGIN_INVALID = 3;
    public static final int LOGIN_ERROR = 4;
    
    /**
    * Create the Session Bean and ensures that the key is not yet valid by
    * setting m_user = null.
    *
    * @throws CreateException 
    *
    * @ejb:create-method view-type="both"
    **/
    public void ejbCreate() throws CreateException {
        m_loginLocal = null;
        m_statusLoggedOn = getLoginStatus(LoginStatusBean.LOGGED_ON);
    }
    
    /**
     *  This gets a local object from a remote object.
     *  @ejb.interface-method view-type="both"
     */
    public com.velocityme.interfaces.KeySessionLocal getLocal() {
        return (KeySessionLocal)m_context.getEJBLocalObject();
    }
    
    /**
     * Attempts to login a user to the system by looking up the user object,
     * checking the password provided is valid and then setting m_user to make
     * the key valid. If any steps fail then the method returns false.
     *
     * @param p_username Name of user trying to login
     * @param p_password Password of user trying to login
     * @param p_clientVersion Version string for the client which must match the server version
     * @return 0 = success, 1 = no available licence, 2 = incorrect password, 3 = invalid user
     *
     * @ejb.interface-method view-type="both"
     **/
    public int login(java.lang.String p_username,
                     java.lang.String p_password,
                     java.lang.String p_clientVersion,
                     java.lang.String p_remoteHost) {
        try {
            // Check that the database has been configured
            SetupDatabase.setupDatabase(p_username, p_password);
            // Load the login statuses once we know they will be available!
            LicenceManager.getInstance();
            // the supplied client version must match the server version in order
            // to proceed with login attempt
            //if (getServerImplementationVersion().equals(p_clientVersion)) {
                UserLocal userLocal = UserUtil.getLocalHome().findByUsername(p_username);
                if (userLocal.getIsEnabled().booleanValue()) {
                    if ((userLocal.getPassword().equals("") && p_password.equals("")) ||
                        userLocal.getPassword().equals(PasswordEncrypter.getInstance().encrypt(p_password))) {
                        // now we must try to assign a suitable licence
                        LicenceManager.getInstance(); // to make sure that old sessions are cleared at startup and timeouts occur
                        m_loginLocal = LicenceKeySessionUtil.getLocalHome().create().assignLicence(userLocal, p_remoteHost);
                        if (m_loginLocal != null) {
                            LoginSessionUtil.getLocalHome().create().limitLoginCount(userLocal);
                            m_logger.info("User " + p_username + " has logged in successfully from client version " + p_clientVersion);
                            return LOGIN_SUCCESS;
                        }
                        else {
                            m_logger.warn("User " + p_username + " could not log in due to no available licence");
                            return LOGIN_LICENCE;
                        }
                    }
                    else {
                        m_logger.warn("User " + p_username + " provided incorrect password");
                        return LOGIN_PASSWORD;
                    }
                }
                else {
                    m_logger.warn("Disabled user " + p_username + " attempting to login");
                    return LOGIN_INVALID;
                }
            //}
            //else
            //    return false;
        }
        catch(CreateException e) {
            return LOGIN_ERROR;
        }
        catch(NamingException e) {
            return LOGIN_ERROR;
        }
        catch(FinderException e) {
            return LOGIN_ERROR;
        }
        catch(com.velocityme.interfaces.ServiceUnavailableException e) {
            return LOGIN_ERROR;
        }
    }
    
    /**
     * Logs out a user and invalidates the key
     *
     * @ejb.interface-method view-type="both"
     **/
    public void logout() {
        if (isValid()) {
            m_logger.info("User " + getUserLocal().getUserName() + " logged out");
            try {
                LicenceKeySessionUtil.getLocalHome().create().releaseLicence(m_loginLocal);
            } catch(NamingException e) {
                throw new EJBException(e);
            } catch(CreateException e) {
                throw new EJBException(e);
            }
        }
        m_loginLocal.setLogoutTime(new Date());
        m_loginLocal.setLoginStatusLocal(getLoginStatus(LoginStatusBean.LOGGED_OFF));
    }
    
    /**
     * Checks to see if this key is currently valid
     *
     * @ejb.interface-method view-type="both"
     **/
    public boolean isValid() {
        LicenceManager.getInstance().pingWatchdog(getLocal());
        try {
            m_loginLocal.setLastActionTime(new Date());
            if (!m_loginLocal.getLoginStatusLocal().equals(m_statusLoggedOn))
                return false;
            return getUserLocal().getIsEnabled() == Boolean.TRUE;
        } catch(Exception e) {
            m_logger.error("Trying to access deleted login");
            return false;
        }
    }
    
    /**
     * Gets the username
     *
     * @ejb.interface-method view-type="both"
     **/
    public java.lang.String getUserName() {
        if (isValid()) {
            return getUserLocal().getUserName();
        }
        return "Invalid key!";
    }
    
    /**
     * Does the user want to see bookmarks?
     *
     * @ejb.interface-method view-type="both"
     **/
    public boolean getShowBookmarks() {
        if (isValid()) {
            return getUserLocal().getShowBookmarks() == Boolean.TRUE;
        }
        return false;
    }
    
    /**
     * Gets the person name
     *
     * @ejb.interface-method view-type="remote"
     **/
    public java.lang.String getPersonName() {
        if (isValid()) {
            return getUserLocal().getPersonLocal().getContactableLocal().getNodeLocal().getName();
        }
        return "Invalid key!";
    }
    
    /**
     * Access to the user holding the key
     *
     * @ejb.interface-method view-type="local"
     **/
    public com.velocityme.interfaces.UserLocal getUserLocal() {
        return m_loginLocal.getUserLocal();
    }
    
    /**
     * Access to the login record
     *
     * @ejb.interface-method view-type="local"
     **/
    public com.velocityme.interfaces.LoginLocal getLoginLocal() {
        return m_loginLocal;
    }
    
    /**
     * Access to the user holding the key
     *
     * @ejb.interface-method view-type="remote"
     **/
    public com.velocityme.interfaces.UserPK getUserPK() {
        return new UserPK(getUserLocal().getUserId());
    }
    
    /**
     * Access to the person holding the key
     *
     * @ejb.interface-method view-type="remote"
     **/
    public com.velocityme.interfaces.PersonPK getPersonPK() {
        return new PersonPK(getUserLocal().getPersonLocal().getPersonId());
    }
    
    /**
     * Access to the server version information
     *
     * @ejb.interface-method view-type="remote"
     **/
    public java.lang.String getServerImplementationVersion() {
        return this.getClass().getPackage().getImplementationVersion();
    }
    
    private LoginStatusLocal getLoginStatus(int p_status) {
        try {
            return LoginStatusUtil.getLocalHome().findByPrimaryKey(new LoginStatusPK(new Integer(p_status)));
        } catch(NamingException e) {
            throw new EJBException(e);
        } catch(FinderException e) {
            throw new EJBException(e);
        }
    }
    
    public void ejbActivate() throws java.rmi.RemoteException {
        m_logger = Logger.getLogger(KeySessionBean.class);
    }
    
    public void ejbPassivate() throws java.rmi.RemoteException {
        m_logger = null;
    }
    
    public void ejbRemove() throws java.rmi.RemoteException {
        logout();
    }
    
    public void setSessionContext(javax.ejb.SessionContext sessionContext) throws java.rmi.RemoteException {
        m_context = sessionContext;
    }
    
}
